using System;

namespace RapidHDL
{

    public enum RapidHardwareEventTypes
    {
        //AfterSettings,
        //BeforeStructure,
        //AfterStructure,
        ConfigureSignalViews,
        //BeforeTest,
        AfterTest,
        //BeforeVerilog,
        //AfterVerilog,
        //BeforeSynthesis,
        //AfterSyntehsis,
        //BeforeClockStart,
        //AfterClockStart,
        HardwareStarted,
        AfterHardwareExecute
    };


	/// <summary>
	/// Summary description for RapidHardware.
	/// </summary>
    /// 
	public class RapidHardware
	{
        public Settings Settings;
		public Simulation Simulation;
		public Structure Structure;
		public InternalLog InternalLog;
        public SystemInterface SystemInterface;
        public FPGAInterface FPGAInterface;
        public Transcript Transcript;
        public HardwareScripts HardwareScripts;

        public DisplayManager DisplayManager;
        
        public delegate bool RapidHardwareEventDelegate(RapidHardware poRapidHardware, RapidHardwareEventTypes pEventType, object oParam1, object oParam2);
        public event RapidHardwareEventDelegate RapidHardwareEvent;

        bool bSettingsReplaced=false;

		public RapidHardware()
		{
            DisplayManager = new DisplayManager();
            Settings = new Settings();
			InternalLog = new InternalLog();
			Simulation = new Simulation(this);
			Structure = new Structure(this);
            SystemInterface = new SystemInterface(this);
            FPGAInterface = new FPGAInterface();
            Transcript = new Transcript();
            HardwareScripts = new HardwareScripts(this);
		}

        public bool StartRapidHardware()
        {
            string sResult;

            Transcript.AddTranscript("Starting Rapid Hardware");

            if (!bSettingsReplaced)
            {
                if (!ConfigureSettings())
                {
                    Transcript.AddTranscript("Error in Configure Settings");
                    return false;
                }
            }

            Settings.Normalize();            
            Structure.ExternalInterface.IntitializeExternalSignalInterface(14, 13, 13, 16);

            if (Settings.RunFromXilinx)
            {
                if (Settings.RemoteFPGAServer == "")
                    FPGAInterface = new PicoInterface();
                else
                {
                    FPGAInterface = new PicoInterfaceRemote(Settings.RemoteFPGAServer);
                    IOInterface.RemotePicoIO = new PicoIOSvc(Settings.RemoteFPGAServer);
                }

            }

            if (Settings.UseClock)
                Structure.TopLevelComponent.AddMainClock(Settings.ClockFrequency);
            if (Settings.UseReset)
                Structure.TopLevelComponent.AddMainReset();
            if (Settings.UseSDRAM)
                Structure.TopLevelComponent.AddSDRAMInterface();
            if (Settings.UseFIFO)
                Structure.TopLevelComponent.AddFIFOInterface();
            if (Settings.UseTestBus)
                Structure.TopLevelComponent.AddTestBus();

            //if (!Settings.UseTestBus)
            //Structure.TopLevelComponent.WireTestBus();


            if (!GenerateStructure(Structure.TopLevelComponent))
            {
                Transcript.AddTranscript("Error in RapidHardware.GenerateStructure");
                return false;
            }

            if (!Structure.GenerateStructure())
            {
                Transcript.AddTranscript("Error in GenerateStructure");
                return false;
            }

            if (!ConfigureSignalViews(Structure.TopLevelComponent))
            {
                Transcript.AddTranscript("Error in ConfigureExternalSignals");
                return false;
            }

            //event
            if (!DoEvent(RapidHardwareEventTypes.ConfigureSignalViews))
                return false;

            if (!GenerateHardwareScripts())
            {
                Transcript.AddTranscript("Error Generating Scripts");
                return false;
            }

            sResult = Simulation.TestComponents();
            if (sResult != "")
            {
                Transcript.AddTranscript(sResult);
                return false;
            }

            if (!DoEvent(RapidHardwareEventTypes.AfterTest))
                return false;

            if (!Structure.GenerateExternalInterface())
                return false;

            if ((Settings.RunFromXilinx || Settings.SimulateVerilog) && !Settings.SkipVerilogGeneration)
            {
                if (!Structure.BuildHardwareSource())
                    return false;

                if (Settings.SimulateVerilog)
                    if (!Structure.SimulateHardwareSource())
                        return false;
            }

            if (Settings.SynthASIC)
            {
                if (!Structure.SynthesizeHardware())
                    return false;

                if (Settings.SimulateVerilog)
                    if (!Structure.SimulateSynthesisSource())
                        return false;
            }

            if (Settings.RunFromXilinx)
            {
                if (!Settings.SkipVerilogGeneration)
                {
                    if (Settings.BuildHardware)
                    {
                        if (Settings.ForceBuildHardware || Structure.FileChanged)
                        {
                            if (!Structure.BuildHardware(true))
                                return false;
                        }
                    }
                }

                LoadRAM();

                sResult = FPGAInterface.Start();
                Transcript.AddTranscript(sResult);
            }
            else
                Structure.ExternalInterface.ConnectSimulation();

            if (!DoEvent(RapidHardwareEventTypes.HardwareStarted))
                return false;

            return true;
        }

        /// <summary>
        /// Give superclass chance to handle event too
        /// </summary>
        /// <param name="pEventType"></param>
        /// <param name="oParam1"></param>
        /// <param name="oParam2"></param>
        /// <returns></returns>
        public virtual bool EventHandler(RapidHardwareEventTypes pEventType, object oParam1, object oParam2)
        {
            return true;
        }

        private bool DoEvent(RapidHardwareEventTypes peType)
        {
            if (!EventHandler(peType, null, null))
            {
                Transcript.AddTranscript("Error in event " + peType.ToString());
                return false;
            }

            if (RapidHardwareEvent == null)
                return true;

            if (!RapidHardwareEvent(this, peType, null, null))
            {
                Transcript.AddTranscript("Error in event " + peType.ToString());
                return false;
            }
            return true;
        }

        public bool SubmitHardwareEvent(RapidHardwareEventTypes peType, object poArg1, object poArg2)
        {
            if (RapidHardwareEvent == null)
                return true;

            return RapidHardwareEvent(this, peType, poArg1,poArg2);
        }


        public virtual bool ConfigureSettings()
        {
            return true;
        }

        public virtual bool GenerateStructure(TopLevelComponent TopLevelComponent)
        {
            //add components
            //add tests
            //add signal sources

            return true;
        }

        public virtual bool ConfigureSignalViews(TopLevelComponent TopLevelComponent)
        {
            //add signals
            //add traces
            //add tests
            return true;
        }

        public virtual bool GenerateHardwareScripts()
        {
            return true;
        }

        public void LaunchGUI(bool pbNewThread)
        {
            FSignals fSignals = new FSignals();
            fSignals.Initialize(this);
            if (pbNewThread)
            {
                System.Windows.Forms.Application.Run(fSignals);
            }
            else
            {
                fSignals.Show();
            }
        }

        public void ReplaceSettings(Settings poSettings)
        {
            bSettingsReplaced = true;
            if (Settings == null)
                Settings = new Settings();
            Settings.CopySettings(poSettings);
            Settings.Normalize(); 
        }

        public virtual MicroTraceData GetMicroTraceData()
        {
            MicroTraceData oMicroTraceData = new MicroTraceData();
            oMicroTraceData.IsValid = false;
            return oMicroTraceData;
        }

        public virtual UCTestInterface GetTestInterface()
        {
            return null;
        }

        public virtual void LoadRAM()
        {
        }

        public virtual string GetActionCaption(int piActionCode)
        {
            return "";
        }

        public virtual void DoAction(int piActionCode)
        {
        }
	}
}
